今天要討論的主題是結構 (Structure),結構是從 C 語言中提出的一種資料結構。它的目的是讓我們可以用來作為變數的集合來同時儲存多個不同資料型態的變數。不過,在物件導向 (Object Orientation)的概念被提出後,從結構為基礎追加了更多進階概念的類別 (Class) 也誕生了。由於類別包含了結構的大多數特質,這使結構漸漸的被類別所取代而變得越來越少被使用,甚至一些以物件導向為基礎的高階程式語言,例如 Java、Python 等,也直接取消了結構的設計,直接使用類別代替。不過,即使改變了存在的方式,結構的概念仍然經常被使用,因此我們今天先了解一下它吧。
試著想像一下,如果今天我們想要建立一個系統來把大量用戶的相關資訊都儲存起來並在需要時把它顯示出來的話,你會怎樣做呢?舉例來說,參考 iT 邦幫忙的會員個人資料,我們現在要儲存的資訊包括:
帳號名稱、密碼、暱稱、姓名、性別、生日、電話、E-mail
從至今為止的提到的程式概念來看,我們可以使用多個變數的陣列來把資訊都儲存起來:[C#]
using System;
public class NotUsingStructExample
{
public static void Main(string[] args)
{
const int UserAmount = 100;
int target;
string[] userAccountNames = new string[UserAmount]; // 帳號名稱
string[] userPasswords = new string[UserAmount]; // 密碼
string[] userNicknames = new string[UserAmount]; // 暱稱
string[] userNames = new string[UserAmount]; // 姓名
string[] userGenders = new string[UserAmount]; // 性別
string[] userBirths = new string[UserAmount]; // 生日
string[] userPhones = new string[UserAmount]; // 電話
string[] userEmails = new string[UserAmount]; // E-mail
...
for (int i = 0; i < UserAmount; i++) {
if (i == target) {
Console.WriteLine(userAccountNames[i]);
Console.WriteLine(userPasswords[i]);
Console.WriteLine(userNicknames[i]);
Console.WriteLine(userNames[i]);
Console.WriteLine(userGenders[i]);
Console.WriteLine(userBirths[i]);
Console.WriteLine(userPhones[i]);
Console.WriteLine(userEmails[i]);
}
}
}
}
可是,當我們宣告了更多的變數或陣列時,這時候程式便會開始變得難以閱讀及管理,試想像一下,如果今天每個用戶需要儲存的資訊不是 8 項而是 100 項的話會如何呢?因此,我們需要一個方法去把這些變數或陣列組合起來,讓我們在管理它們時更方便一點。而結構便是在這情況下被提出的解決方法:[C#]
using System;
public class StructExample
{
// 用戶資料的結構
public struct UserInfo {
string accountName; // 帳號名稱
string password; // 密碼
string nickname; // 暱稱
string name; // 姓名
string gender; // 性別
string birth; // 生日
string phone; // 電話
string email; // E-mail
// 準備一個函式來把用戶資料顯示出來
public void showInfo() {
Console.WriteLine(accountName);
Console.WriteLine(password);
Console.WriteLine(nickname);
Console.WriteLine(name);
Console.WriteLine(gender);
Console.WriteLine(birth);
Console.WriteLine(phone);
Console.WriteLine(email);
}
}
public static void Main(string[] args)
{
const int UserAmount = 100;
int target;
UserInfo[] users = new UserInfo[UserAmount]; // 用戶資料結構的陣列
...
for (int i = 0; i < UserAmount; i++) {
if (i == target) {
users[i].showInfo(); // 呼叫結構的函數來把用戶資料顯示出來
}
}
}
}
我們可以發現實際上結構只是把變數都放在一起,並沒有讓程式碼變少,不過它卻能讓主函式的部分變得更簡潔。而且,我們也可以讓針對資料的處理都以函數的方式放到結構中來進一步簡化主函式,如此一來,我們的程式便可以更容易的被閱讀及管理。即使我們要在後續的更新中增加其他的資料也會看起來比較沒有那麼混亂。舉例來說,我們現在要增加一個顯示商品的系統:[C#]
using System;
public class MoreStructExample
{
// 用戶資料的結構
public struct UserInfo {
string accountName; // 帳號名稱
string password; // 密碼
string nickname; // 暱稱
string name; // 姓名
string gender; // 性別
string birth; // 生日
string phone; // 電話
string email; // E-mail
public void showInfo() {
... // 顯示用戶資訊
}
}
// 商品資料的結構
public struct ProductInfo {
string name; // 商品名稱
string desciption; // 商品說明
int price; // 商品價格
int amount; // 商品數量
public void showInfo() {
... // 顯示商品資訊
}
public void buy() {
... // 購買商品
}
}
public static void Main(string[] args)
{
const int UserAmount = 100;
const int ProductType = 50;
UserInfo[] users = new UserInfo[UserAmount]; // 用戶資料結構的陣列
ProductInfo[] products = new ProductInfo[ProductType]; // 商品資料結構的陣列
...
}
}
我們把用戶資料跟商品資料的變數及行為分開儲存在不同的結構中,便可以透過結構的名稱來分辨及管理它們所代表的資料。當我們需要修改什麼資料的部分時,就在該資料的結構中修改,而需要新增新的資料與行為時,則為新的資料新增新的結構。這樣一來,我們在後續的更新跟維護時程式碼便會相對沒有分類的情況下更易於閱讀跟清晰了。
同樣地,我們也可以使用類別來達到相同的目的:[Python]
class UserInfo: # 用戶資料的類別
accountName = "" # 帳號名稱
password = "" # 密碼
nickname = "" # 暱稱
name = "" # 姓名
gender = "" # 性別
birth = "" # 生日
phone = "" # 電話
email = "" # E-mail
def showInfo():
... # 顯示用戶資訊
class ProductInfo: # 商品資料的類別
name = "" # 商品名稱
desciption = "" # 商品說明
price = 0 # 價格
amount = 0 # 商品數量
def showInfo():
... # 顯示商品資訊
def buy():
... # 購買商品
# 主函式的部分
users = []
products = []
for i in range(0,100):
users.append(UserInfo())
for i in range(0,50):
users.append(ProductInfo())
...